package com.wan37.logic.trading.handler;

import com.wan37.common.uuid.UUIDUtil;
import com.wan37.logic.backpack.item.ItemManager;
import com.wan37.logic.backpack.weaponry.WeaponryManager;
import com.wan37.logic.component.Worker;
import com.wan37.logic.db.AsynDBManager;
import com.wan37.logic.domain.Result;
import com.wan37.logic.domain.entity.UserDO;
import com.wan37.logic.domain.vo.MessageVO;
import com.wan37.logic.global.reference.SpringContextHolder;
import com.wan37.logic.handler.MsgHandler;
import com.wan37.logic.listener.EventDispatcher;
import com.wan37.logic.listener.event.EventType;
import com.wan37.logic.listener.event.user.UserTradingEvent;
import com.wan37.logic.service.UserService;
import com.wan37.logic.service.cache.SceneServiceCache;
import com.wan37.logic.service.cache.UserServiceCache;
import com.wan37.logic.trading.cache.TradingCache;
import com.wan37.logic.trading.domain.vo.TradingVO;
import com.wan37.logic.trading.util.TradingRouteUtil;
import com.wan37.logic.utils.RouteUtils;
import com.wan37.protobuf.constant.BackpackLabel;
import com.wan37.protobuf.constant.CommonTrading;
import com.wan37.protobuf.constant.ShopLabel;
import com.wan37.protobuf.message.client2server.game.GameTrading;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : luoyong
 * @date : 2020-07-31 14:42
 **/
public class CGameTradingHandler extends MsgHandler {
    private UserServiceCache userServiceCache;
    private TradingCache tradingCache;
    private TradingRouteUtil tradingRouteUtil;
    private ItemManager itemManager;
    private WeaponryManager weaponryManager;
    private AsynDBManager asynDBManager;
    private UserService userService;
    private RouteUtils routeUtils;
    private SceneServiceCache sceneServiceCache;
    /**
     * MsgHandler构造函数
     *
     * @param messageVO
     */
    public CGameTradingHandler(MessageVO messageVO) {
        super(messageVO);
        this.userServiceCache = SpringContextHolder.getBean("userServiceCache");
        this.tradingCache = SpringContextHolder.getBean("tradingCache");
        this.tradingRouteUtil = SpringContextHolder.getBean("tradingRouteUtil");
        this.itemManager = SpringContextHolder.getBean("itemManager");
        this.weaponryManager = SpringContextHolder.getBean("weaponryManager");
        this.asynDBManager = SpringContextHolder.getBean("asynDBManager");
        this.userService = SpringContextHolder.getBean("userService");
        this.routeUtils = SpringContextHolder.getBean("routeUtils");
        this.sceneServiceCache = SpringContextHolder.getBean("sceneServiceCache");
    }

    @Override
    public void execute(Worker worker) throws Exception {
        GameTrading.TradingMsg tradingMsg = (GameTrading.TradingMsg) messageVO.getMessage();
        int code = tradingMsg.getCode();
        String userId = messageVO.getUserId();
        UserServiceCache.User user = userServiceCache.getUserServiceMap().get(userId);
        switch (code){
            case CommonTrading.GET_ALL:
                if (user.getInTradingUserId() == null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.NOT_IN_TRADING, userId, null);
                    break;
                }
                tradingRouteUtil.sendTradingResponse(CommonTrading.GET_ALL,
                        new ArrayList<>(user.getTradingIdToTradingVOMap().values()), userId);
                break;
            case CommonTrading.REQUEST:
                String senderId = userId;
                String receiverId = tradingMsg.getStringId();
                if (senderId.equals(receiverId)){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.ERROR, "不可以与自己进行交易！", senderId, null);
                    break;
                }
                if (userServiceCache.getUserServiceMap().get(senderId).getInTradingUserId() != null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.IN_TRADING, "你已经在交易中，不允许再次发起交易！", senderId, null);
                    break;
                }
                boolean flag = true;
                for (String s : sceneServiceCache.getSceneServiceMap().get(
                        userServiceCache.getUserServiceMap().get(senderId).getSceneId()).getUserIdSet()){
                    if (s.equals(receiverId)){
                        flag = false;
                        break;
                    }
                }
                if (flag){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.ERROR, "选择的对象不在线或者不在同一个场景中！", senderId, null);
                    break;
                }
                if (userServiceCache.getUserServiceMap().get(receiverId).getInTradingUserId() != null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.IN_TRADING, "对方正在交易中，不允许您发起交易请求", senderId, null);
                    break;
                }
                if (!tradingCache.getRequestTradingIdMap().containsKey(senderId)){
                    tradingCache.getRequestTradingIdMap().put(senderId, new ArrayList<>());
                }
                tradingCache.getRequestTradingIdMap().get(senderId).add(receiverId);
                tradingRouteUtil.sendTradingResponse(CommonTrading.REQUEST, senderId, receiverId, null);
                break;
            case CommonTrading.CANCEL:
                if (user.getInTradingUserId() == null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.ERROR, "并不在交易状态中！", userId, null);
                    break;
                }
                //将对方的交易状态取消
                userServiceCache.getUserServiceMap().get(user.getInTradingUserId()).setInTradingUserId(null);
                userServiceCache.getUserServiceMap().get(user.getInTradingUserId()).setTradingIdToTradingVOMap(null);
                tradingRouteUtil.sendTradingResponse(CommonTrading.CANCEL, userId, user.getInTradingUserId(), null);
                //将自己的交易状态取消
                tradingRouteUtil.sendTradingResponse(CommonTrading.CANCEL, user.getInTradingUserId(), userId, null);
                user.setInTradingUserId(null);
                user.setTradingIdToTradingVOMap(null);
                break;
            case CommonTrading.RESPONSE:
                String senderId1 = userId;
                String receiverId1 = tradingMsg.getStringId();

                if (userServiceCache.getUserServiceMap().get(senderId1).getInTradingUserId() != null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.IN_TRADING, "你已经在交易中，不允许再次发起交易！", senderId1, null);
                    break;
                }
                if (userServiceCache.getUserServiceMap().get(receiverId1).getInTradingUserId() != null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.IN_TRADING, "对方已经和别人在交易了！", senderId1, null);
                    break;
                }
                boolean flag1 = true;
                if (tradingCache.getRequestTradingIdMap().containsKey(receiverId1)){
                    for (String s : tradingCache.getRequestTradingIdMap().get(receiverId1)){
                        if (s.equals(senderId1)){
                            flag1 = false;
                            break;
                        }
                    }
                }else {
                    tradingRouteUtil.sendTradingResponse(CommonTrading.ERROR, "对方并没有发起交易请求连接！", senderId1, null);
                    return;
                }
                if (flag1){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.ERROR, "对方并没有发起交易请求连接！", senderId1, null);
                    return;
                }
                userServiceCache.getUserServiceMap().get(senderId1).setInTradingUserId(receiverId1);
                userServiceCache.getUserServiceMap().get(senderId1).setTradingIdToTradingVOMap(new HashMap<>());
                userServiceCache.getUserServiceMap().get(receiverId1).setInTradingUserId(senderId1);
                userServiceCache.getUserServiceMap().get(receiverId1).setTradingIdToTradingVOMap(new HashMap<>());
                tradingRouteUtil.sendTradingResponse(CommonTrading.RESPONSE, senderId1, receiverId1, null);
                tradingRouteUtil.sendTradingResponse(CommonTrading.RESPONSE, receiverId1, senderId1, null);
                break;
            case CommonTrading.SEND_TRADING:
                if (user.getInTradingUserId() == null){
                    tradingRouteUtil.sendTradingResponse(CommonTrading.NOT_IN_TRADING, userId, null);
                    break;
                }
                TradingVO tradingVO = new TradingVO(tradingMsg.getTrading());
                user.getTradingIdToTradingVOMap().put(tradingVO.getTradingId(), tradingVO);
                tradingRouteUtil.sendTradingResponse(CommonTrading.SEND_TRADING, userId, tradingMsg.getStringId(), tradingVO);
                break;
            case CommonTrading.RECEIVE_TRADING_AGREE:
                Map<String, TradingVO> tradingIdToTradingVOMap = userServiceCache
                        .getUserServiceMap().get(user.getInTradingUserId()).getTradingIdToTradingVOMap();
                TradingVO tradingVO1 = tradingIdToTradingVOMap.get(tradingMsg.getStringId());
                /**
                 * 校验数值
                 */
                Result senderResult = isSenderEnough(userServiceCache.getUserServiceMap().get(tradingVO1.getSenderId()), tradingVO1);
                if (senderResult.getCode() == CommonTrading.ERROR){
                    tradingRouteUtil.sendTradingResponse(senderResult.getCode(), senderResult.getContent(), tradingVO1.getSenderId(), null);
                    tradingRouteUtil.sendTradingResponse(senderResult.getCode(), senderResult.getContent(), tradingVO1.getReceiverId(), null);
                    break;
                }
                Result receiverResult = isReceiverEnough(userServiceCache.getUserServiceMap().get(tradingVO1.getReceiverId()), tradingVO1);
                if (receiverResult.getCode() == CommonTrading.ERROR){
                    tradingRouteUtil.sendTradingResponse(senderResult.getCode(), senderResult.getContent(), tradingVO1.getSenderId(), null);
                    tradingRouteUtil.sendTradingResponse(senderResult.getCode(), senderResult.getContent(), tradingVO1.getReceiverId(), null);
                    break;
                }
                /**
                 * 数值处理
                 */
                tradingNumberHandler(tradingVO1);
                tradingRouteUtil.sendTradingResponse(CommonTrading.RECEIVE_TRADING_AGREE, tradingVO1.getSenderId(), tradingVO1.getReceiverId(), tradingVO1);
                tradingRouteUtil.sendTradingResponse(CommonTrading.RECEIVE_TRADING_AGREE, tradingVO1.getReceiverId(), tradingVO1.getSenderId(), tradingVO1);
                //将交易完成的消息移除
                tradingIdToTradingVOMap.remove(tradingVO1.getTradingId());
                break;
            case CommonTrading.RECEIVE_TRADING_DISAGREE:
                Map<String, TradingVO> tradingIdToTradingVOMap1 = userServiceCache
                        .getUserServiceMap().get(user.getInTradingUserId()).getTradingIdToTradingVOMap();
                TradingVO tradingVO2 = tradingIdToTradingVOMap1.get(tradingMsg.getStringId());
                tradingRouteUtil.sendTradingResponse(CommonTrading.RECEIVE_TRADING_DISAGREE, tradingVO2.getSenderId(), tradingVO2.getReceiverId(), tradingVO2);
                tradingRouteUtil.sendTradingResponse(CommonTrading.RECEIVE_TRADING_DISAGREE, tradingVO2.getReceiverId(), tradingVO2.getSenderId(), tradingVO2);
                //将交易完成的消息移除
                tradingIdToTradingVOMap1.remove(tradingVO2.getTradingId());
                break;
            default:
                break;
        }
    }

    public void tradingNumberHandler(TradingVO tradingVO){
        UserServiceCache.User sender = userServiceCache.getUserServiceMap().get(tradingVO.getSenderId());
        UserServiceCache.User receiver = userServiceCache.getUserServiceMap().get(tradingVO.getReceiverId());
        if (tradingVO.getType() == ShopLabel.MONEY_TYPE_GOLD){
            sender.getUserVO().setGold(sender.getUserVO().getGold() - tradingVO.getGold());
            receiver.getUserVO().setGold(receiver.getUserVO().getGold() + tradingVO.getGold());
        }
        if (tradingVO.getType() == BackpackLabel.WEAPONRY){
            for (Map.Entry<String, Integer> entry : tradingVO.getBackpackIdToCountMap().entrySet()){
                //同意交易方得到装备
                weaponryManager.addWeaponry(tradingVO.getReceiverId(), sender.getWeaponryVOMap().get(entry.getKey()));
                //交易发送方减少装备
                weaponryManager.reduceWeaponry(tradingVO.getSenderId(), entry.getKey());
            }
        }
        if (tradingVO.getType() == BackpackLabel.ITEM){
            for (Map.Entry<String, Integer> entry : tradingVO.getBackpackIdToCountMap().entrySet()){
                itemManager.reduceItem(sender, entry.getKey(), entry.getValue());
                itemManager.addItem(receiver, entry.getKey(), entry.getValue());
            }
        }
        //发送方增加元宝数量
        sender.getUserVO().setIngot(sender.getUserVO().getIngot() + tradingVO.getIngot());
        //保存发送方金币、元宝数值信息，并且推送客户端
        UserDO senderDO = new UserDO(sender.getUserVO());
        asynDBManager.distributeWork(sender.getUserVO().getUserId(), ()->userService.update(senderDO));
        routeUtils.sendUserVO(sender.getUserVO());
        //同意方减少元宝数量
        receiver.getUserVO().setIngot(receiver.getUserVO().getIngot() - tradingVO.getIngot());
        //保存同意方金币、元宝数值信息，并且推送客户端
        UserDO receiverDO = new UserDO(receiver.getUserVO());
        asynDBManager.distributeWork(receiver.getUserVO().getUserId(),()->userService.update(receiverDO));
        routeUtils.sendUserVO(receiver.getUserVO());
        EventDispatcher.getInstance().fireEvent(new UserTradingEvent(EventType.TRADING, tradingVO.getSenderId()));
    }

    /**
     * 校验交易信息发送方交易货物是否充足
     * @param user
     * @param tradingVO
     * @return
     */
    public Result isSenderEnough(UserServiceCache.User user, TradingVO tradingVO){
        if (tradingVO.getType() == ShopLabel.MONEY_TYPE_GOLD){
            if (user.getUserVO().getGold() - tradingVO.getGold() >= 0){
                return new Result(1, null);
            }
            return new Result(CommonTrading.ERROR, "金币余额不足！！");
        }
        if (tradingVO.getType() == BackpackLabel.ITEM){
            for (Map.Entry<String, Integer> entry : tradingVO.getBackpackIdToCountMap().entrySet()){
                if (user.getItemVOMap().get(entry.getKey()).getCount() - entry.getValue() < 0 ){
                    return new Result(CommonTrading.ERROR, "物品数量不足！");
                }
            }
            return new Result(1, null);
        }
        if (tradingVO.getType() == BackpackLabel.WEAPONRY){
            for (Map.Entry<String, Integer> entry : tradingVO.getBackpackIdToCountMap().entrySet()){
                if (!user.getWeaponryVOMap().containsKey(entry.getKey())){
                    return new Result(CommonTrading.ERROR, "交易的装备不存在！！");
                }
                if (!user.getWeaponryVOMap().get(entry.getKey()).getUsage().equals(BackpackLabel.WEAPONRY_UNUSED)){
                    return new Result(CommonTrading.ERROR, "已经在角色中使用的装备，不允许交易！");
                }
            }
            return new Result(CommonTrading.SUCCESS, null);
        }
        return new Result(CommonTrading.ERROR, "只允许交易金币或物品！");
    }

    /**
     * 校验交易同意方元宝是否充足
     * @param user
     * @param tradingVO
     * @return
     */
    public Result isReceiverEnough(UserServiceCache.User user, TradingVO tradingVO){
        if (user.getUserVO().getIngot() - tradingVO.getIngot() < 0){
            return new Result(CommonTrading.ERROR, "元宝不足，交易失败，请充钱，谢谢！");
        }
        return new Result(CommonTrading.SUCCESS, null);
    }
}
